#ifndef __CAPAINDICES_ARBOLBMAS_H
#define __CAPAINDICES_ARBOLBMAS_H

/*****************************************************************************
*                     Organizacion de Datos - 75.06                          *
*                         Catedra Lic. Servetto                              *
*            Facultad de Ingenieria - Universidad de Buenos Aires            *
******************************************************************************/

#include "Indices.h"

using namespace std;
using namespace Comun;

namespace CapaIndices
{

	// Enumera los tipos posibles de Nodos.
	enum TipoNodo
	{

		// Nodo interno del arbol. Contiene referencias a otros nodos.
		Interno,
		// Nodo hoja del arbol. Contiene referencias a datos o listas de claves primarias.
		Hoja

	};


	typedef list<MetadatosAtributo>::iterator IteradorDeMetadatosAtributos;
	typedef list<ClaveValor>::iterator IteradorDeClaveValor;

	// Representa el resultado de una operaci�n
	struct Resultado
	{

		// C�digo del resultado
		CodigoResultado Codigo;
		// Mensaje con informaci�n sobre el resultado
		string mensaje;

	};

	// Clase que representa a un nodo de un �rbol.
	class Nodo : public Grupo
	{

	public:
		Nodo(Grupo grupo);
		Nodo();
		~Nodo();
		
		void Sincronizar(bool esDato);

		// Identificador del nodo.
		int NodoId;
		// Referencia al nodo siguiente. Utilizado en lectura secuencial.
		int HijoIzquierdo;
		// Referencia al nodo siguiente. Utilizado en lectura secuencial.
		int NodoSiguiente;
		// Referencia al nodo anterior. Utilizado en lectura secuencial.
		int NodoAnterior;
		// Contador de indicadores presentes en el nodo.
		short Contador;
		// Tipo del nodo, Interno u Hoja.
		TipoNodo Tipo;
		// Referencia al nodo anterior. Utilizado en lectura secuencial.
		int GrupoDesborde;

		list<Atributo>* OtrosAtributos;

	private:
		bool sincronizado;

	};

	typedef list<Nodo>::iterator IteradorDeNodos;
	typedef list<Nodo*>::iterator IteradorDePunterosANodo;

	// �ndice implementado sobre la estructura de un �rbol B+. Implementa la interfaz IIndice.
	class ArbolBMas : public IIndice
	{

	public:
		ArbolBMas(MetadatosIndice* metadata);
		~ArbolBMas();

		// Crea un nuevo indice a partir de la metadata suministrada.
		bool Crear();

		void CrearArchivosEnMemoria();

		// Inserta 'clave' en el inidce.
		void InsertarClave(Clave* clave);

		// Busca el registro representado por 'clave' y le asigna sus campos.
		void BuscarClave(Clave* clave);

		// Elimina el registro representado por 'clave'
		void EliminarClave(Clave* clave);

		// Actualiza los cambios producidos al registro representado por 'clave'
		void ActualizarClave(Clave* clave);


		// Crea un nodo del tipo especificado en la referencia 'nodo'.
		Resultado CrearNodo ( TipoNodo tipo, Nodo** nodo );
		// Busca el nodo identificado por 'nodoId' y lo coloca en la referencia 'nodo'.
		Resultado BuscarNodo ( int nodoId, Nodo** nodo );
		// Elimina el nodo identificado por 'nodoId'
		Resultado EliminarNodo ( int nodoId );
		// Actualiza el nodo.
		Resultado ActualizarNodo ( Nodo** nodo );
		Resultado ActualizarNodo ( Nodo** nodo, bool omitirSubflujo);
		// Puntero al nodo raiz.
		Nodo* ObtenerNodoRaiz();
		Registro CrearIndicador(Registro registroDatos);

		IArchivo* ArchivoIndice;
		IArchivo* ArchivoDatos;

	private:
		bool archivosCreados;


	};

	int obtenerIdHijoDerecho(Registro r );

	// Clase abstracta que representa una estrategia utilizada para llevar a cabo una operaci�n sobre el nodo.
	class Estrategia
	{

	public:
		Estrategia(ArbolBMas *arbol,bool multiple);
		Estrategia(ArbolBMas *arbol);
		virtual ~Estrategia();

		bool Multiple;
		// Localiza el registro en el �ndice identificado por 'clave'.
		Resultado LocalizarClave(Clave* clave);
		bool ObtenerSiguiente(Nodo** padre, Nodo** siguiente);
		bool ObtenerAnterior(Nodo** padre, Nodo** siguiente);
		// Verifica el rango de aplicaci�n de la clave sobre el nodo, y devuelve el siguiente nodo
		// si es que la condici�n va m�s all� del nodo.
		bool VerificarRangoCondicion(Clave *clave, Nodo *nodo, Nodo** padre, Registro* localizador, Nodo** siguiente);
		// Ejecuta la estrategia sobre la clave identificada por 'clave'
		virtual Resultado EjecutarEstrategia(Clave* clave) = 0;
		// Lista que contiene el conjunto de nodos que conforman el camino hasta la clave (encontrada o donde
		// deberia haberse encontrado). Sirve como pila de ejecucion.
		list<Nodo*> Camino;

	protected:
		ArbolBMas* Arbol;
	};

	list<Atributo>* ExtraerAtributosClave(list<Atributo>* r, list<MetadatosAtributo> camposClave);

	// Estrategia para la insercion de una clave.
    class EstrategiaInsercion : public Estrategia
    {
    public:
        EstrategiaInsercion(ArbolBMas *arbol);
        ~EstrategiaInsercion();

        Resultado EjecutarEstrategia(Clave* clave);
        bool Sobreescribir;
    private:
        int BuscarElGrupo(Nodo nodo,Clave clave);
		Resultado InsertarEnIndice(IteradorDePunterosANodo nodo, Registro* orientador);
        CodigoResultado InsertarEnNodo(Nodo* nodo, Registro reg);
        Grupo PartirGrupo(Grupo* grupo);
        int CalcularTamGrupo(Grupo grupo);
        string BuscarClaveDelGrupo(Grupo grupo);
        Registro* PartirNodo(Nodo* nodo, TipoNodo tipo);
        Registro* SepararPrimerRegistro(Nodo* nodo);
        int BuscarHijoIzq(Nodo nodo,Registro RegdelNodo);
		void PrimerInsercion(Clave* clave);
		Resultado* InsercionPolivalente(Nodo* nodo, Clave* clave);
		Resultado* InsercionMonovalente(Nodo* nodo, Clave* clave);
		Resultado* InsercionSecundario(Nodo* nodo, Clave* clave, bool existe, bool desborde);
		Resultado* ResolverSobreflujoPolivalente(Grupo* grupo2,CodigoResultado res2);
    };

	// Estrategia para la insercion de una clave.
	class EstrategiaActualizacion : public Estrategia
	{
	public:
		EstrategiaActualizacion(ArbolBMas *arbol, bool multiple);
		~EstrategiaActualizacion();

		Resultado EjecutarEstrategia(Clave* clave);
	private:
		//
		Resultado ActualizacionRecursiva(Clave* clave, Nodo* nodo,Nodo** padre, Registro* localizador);
		//
		void ActualizarRegistrosEnSecundario(Nodo* nodo, Clave* clave,Registro* localizador, MetadatosIndice metadata);

		Resultado ActualizarRegistro(Clave* clave, Registro* registro );


	};

	// Estrategia para la eliminacion de una clave.
	class EstrategiaEliminacion : public Estrategia
	{
	public:
		EstrategiaEliminacion(ArbolBMas *arbol, bool multiple);
		~EstrategiaEliminacion();

		Resultado EjecutarEstrategia(Clave* clave);

	private:
		//
		Resultado* BorradoRecursivo(Clave* clave, Nodo* nodo,Nodo** padre, Registro* localizador, bool hallado);
		//
		void BorrarRegistrosEnSecundario(Nodo* nodo, Clave* clave,Registro* localizador, MetadatosIndice metadata);
		//
		void BorrarRegistrosEnMonovalente(Nodo* nodo, Clave* clave,Registro* localizador);
		//
		void BorrarRegistrosEnPolivalente(Nodo* nodo, Clave* clave,Registro* localizador);
		//
		Resultado* TraspasarRegistro(bool izquierdo, Nodo* padre, Grupo* nodo, Grupo* hermano, Registro* indicador, Registro traspaso);
		//
		Resultado* ActualizarNodo(Nodo *nodo, Registro *regAEliminar, IteradorDePunterosANodo camino, Grupo* fusionado, bool hijoIzquierdo);
		//
		Resultado* ActualizarGrupoDeDatos(Nodo* nodo);
		//
		Resultado* FusionarNodos(bool izquierdo, Nodo* padre, Nodo* nodo, Nodo* hermano, Registro* indicador, IteradorDePunterosANodo camino);
		//
		Resultado* FusionarNodosDatos(bool izquierdo, Nodo* padre, Grupo* nodo, Grupo* hermano, Registro* indicador);

	};

	// Estrategia para la busqueda de una clave.
	class EstrategiaBusqueda : public Estrategia
	{
	public:
		EstrategiaBusqueda(ArbolBMas *arbol,bool multiple);
		EstrategiaBusqueda(ArbolBMas *arbol);
		~EstrategiaBusqueda();

		Resultado EjecutarEstrategia(Clave *clave);

	private:
		//
		Resultado BusquedaRecursiva(Clave* clave, Nodo* nodo,Nodo** padre, Registro* localizador, bool hallado);
		//
		void BuscarRegistrosEnSecundario(Nodo* nodo, Clave* clave,Registro* localizador, MetadatosIndice metadata);

	};

	class ArchivoTemp : public IArchivo{

	public:
		ArchivoTemp(string nombre);
		virtual ~ArchivoTemp();

		int CrearGrupo(Comun::Grupo &grupo);
		CodigoResultado GuardarGrupo(Comun::Grupo &grupo, bool omitirSubflujo = false);
		Comun::Grupo& LeerGrupo(int grupoId);
		void BorrarGrupo(int grupoId);
		int PrimerGrupo();
		int SiguienteGrupo(int grupoIdActual);
		Comun::Grupo* actual;
		void Crear();

	private:
		list<Comun::Grupo>* grupos;
		Nodo** nodos;
		int lastId;

	};

}

#endif
